package com.punch.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.punch.common.dto.user.menu.MenuDTO;
import com.punch.common.exception.BusinessException;
import com.punch.common.model.SysMenu;
import com.punch.common.service.impl.SuperServiceImpl;
import com.punch.common.vo.user.menu.MenuTreeVO;
import com.punch.common.vo.user.menu.SimpleMenuTreeVO;
import com.punch.user.exception.UserExceptionEnum;
import com.punch.user.mapper.SysMenuMapper;
import com.punch.user.service.MenuService;
import com.punch.user.util.MenuUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 作者 owen E-mail: 624191343@qq.com
 */
@Slf4j
@Service
public class MenuServiceImpl extends SuperServiceImpl<SysMenuMapper, SysMenu> implements MenuService {


    /**
     * 菜单树
     *
     * @return List<MenuTreeVO>
     */
    @Override
    public List<MenuTreeVO> treeMenu() {
        Map<Long, List<SysMenu>> menuMap = menuList().stream().collect(Collectors.groupingBy(SysMenu::getParentId));
        return MenuUtil.handlerMenuTree(menuMap, 0L);
    }

    /**
     * 简单菜单树,用于角色选择菜单
     *
     * @return List<MenuTreeVO>
     */
    @Override
    public List<SimpleMenuTreeVO> treeSimpleMenu() {
        Map<Long, List<SysMenu>> menuMap = menuList().stream().collect(Collectors.groupingBy(SysMenu::getParentId));
        return MenuUtil.handlerSimpleMenuTree(menuMap, 0L);
    }


    /**
     * 新增菜单
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Long saveMenu(MenuDTO menuDTO) {
        //数据重复校验
        menuRepeatCheck(menuDTO.getTitle(), menuDTO.getParentId(), menuDTO.getApplication(), 0L);
        SysMenu menu = new SysMenu();
        BeanUtils.copyProperties(menuDTO, menu);
        //判断是否有父级
        SysMenu parentMenu = null;
        if (menuDTO.getParentId() != null && menuDTO.getParentId() != 0L) {
            parentMenu = getById(menu.getParentId());
            if (null == parentMenu) {
                throw new BusinessException(UserExceptionEnum.PARENT_DATA_DOES_NOT_EXIST);
            }
            menu.setParentTitle(parentMenu.getParentTitle());
        }
        menu.setCreateTime(LocalDateTime.now());
        menu.setUpdateTime(LocalDateTime.now());
        if (!save(menu)) {
            throw new BusinessException(UserExceptionEnum.DATA_INSERT_EXCEPTION);
        }
        //数据保存成功,父级"直接子集数量"加1
        if (null != parentMenu) {
            getBaseMapper().addChildNum(parentMenu.getId());
        }
        return menu.getId();

    }


    /**
     * 修改菜单
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Long updateMenu(MenuDTO menuDTO) {
        if (menuDTO.getMenuId().equals(menuDTO.getParentId())) {
            throw new BusinessException(UserExceptionEnum.PARENT_CAN_NOT_BE_SELF);
        }
        //数据重复校验
        menuRepeatCheck(menuDTO.getTitle(), menuDTO.getParentId(), menuDTO.getApplication(), menuDTO.getMenuId());
        SysMenu menu = new SysMenu();
        BeanUtils.copyProperties(menuDTO, menu);
        menu.setId(menuDTO.getMenuId());
        SysMenu sysMenuEx = getById(menuDTO.getMenuId());

        //隐藏菜单子级菜单也隐藏,显示菜单子级也显示
        if (!menuDTO.getHidden().equals(sysMenuEx.getHidden())) {
            List<Long> childIdList = getBaseMapper().selectAllChildIdByPid(menuDTO.getMenuId());
            if (CollUtil.isNotEmpty(childIdList)) {
                getBaseMapper().updateMenuStatusByList(childIdList, menuDTO.getHidden());
            }
        }
        //如果父级是隐藏，子级不能修改成显示
        if (1 == menuDTO.getHidden() && sysMenuEx.getParentId() != 0) {
            SysMenu parent = getById(sysMenuEx.getParentId());
            if (parent.getHidden() == 0) {
                throw new BusinessException(UserExceptionEnum.PARENT_MENU_IS_HIDDEN);
            }
        }
        if (!updateById(menu)) {
            throw new BusinessException(UserExceptionEnum.DATA_UPDATE_EXCEPTION);
        }
        return menuDTO.getMenuId();

    }


    /**
     * 删除菜单
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Long deleteMenu(Long menuId) {
        //校验数据是否存在
        SysMenu sysMenuEx = getById(menuId);
        if (null == sysMenuEx) {
            throw new BusinessException(UserExceptionEnum.MENU_NOT_EXIST);
        }
        //删除自身
        if (!removeById(menuId)) {
            throw new BusinessException(UserExceptionEnum.DATA_DELETION_EXCEPTION);
        }
        //删除子级
        //查找子级
        List<Long> childIdList = getBaseMapper().selectAllChildIdByPid(menuId);
        removeByIds(childIdList);
        //如有父级，则父级“直接子集数量”减1
        if (0L != sysMenuEx.getParentId()) {
            SysMenu parentMenu = getById(sysMenuEx.getParentId());
            if (null == parentMenu) {
                throw new BusinessException(UserExceptionEnum.PARENT_DATA_DOES_NOT_EXIST);
            }
            // 原来上级子节点数量 -1
            getBaseMapper().subChildNum(sysMenuEx.getParentId());
        }
        return menuId;

    }

    /**
     * 验证菜单是否重复
     *
     * @param title       菜单名称
     * @param application 所属应用
     * @param menuId      菜单主键id
     * @author wujj
     * @since 2020/6/5 11:21
     */
    private void menuRepeatCheck(String title, Long parentId, String application, Long menuId) {
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(SysMenu::getTitle, title)
                .eq(SysMenu::getApplication, application)
                .eq(SysMenu::getParentId, parentId);
        if (menuId != 0L) {
            queryWrapper.lambda().notIn(SysMenu::getId, menuId);
        }
        if (count(queryWrapper) > 0) {
            throw new BusinessException(UserExceptionEnum.MENU_NAME_REPEAT);
        }
    }


    private List<SysMenu> menuList() {
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByAsc(SysMenu::getSortBy);
        List<SysMenu> list = list(queryWrapper);
        return list;
    }


}
